#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/ide.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/gpio.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/of_gpio.h>
#include <linux/semaphore.h>
#include <linux/timer.h>
#include <linux/irq.h>
#include <linux/wait.h>
#include <linux/poll.h>
#include <linux/fs.h>
#include <linux/fcntl.h>
#include <linux/platform_device.h>
#include <asm/mach/map.h>
#include <asm/uaccess.h>
#include <asm/io.h>

#define KeyDEV_CNT		1			/* 设备数量 	*/
#define KeyDEV_NAME		"keyled"	/* 设备名字 	*/

/* 寄存器名 */
static void __iomem *IMX6U_CCM_CCGR1;
static void __iomem *SW_MUX_GPIO1_IO018;
static void __iomem *SW_PAD_GPIO1_IO018;
static void __iomem *GPIO1_DR;
static void __iomem *GPIO1_GDIR;

static struct cdev key_dev;        //字符设备
dev_t devid;                //设备号
struct class *class;	
struct device *device;

static int key_open(struct inode *inode, struct file *filp)
{
    return 0;
}
static ssize_t key_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{
    return 0;
}
static ssize_t key_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{
    // u32 ret;
    int value;
    value = readl(GPIO1_DR);
    printk("value : %d\r\n",(value>>18)&0x01);
    // ret = copy_to_user(buf, &value, sizeof(value));
    // return ret;
    return 0;
}

static struct file_operations key_fops = {
	.owner = THIS_MODULE,
	.open = key_open,
	.write = key_write,
    .read = key_read,
};


static int Keyprobe(struct platform_device *dev)
{
    int i = 0;
	int ressize[5];
	u32 val = 0;
	struct resource *ledsource[5];

	printk("key driver and device has matched!\r\n");
	printk("platform_device name:%s,num:%d\r\n",dev->name,dev->num_resources);
	for (i = 0; i < 5; i++) {
		ledsource[i] = platform_get_resource(dev, IORESOURCE_MEM, i); /* 依次MEM类型资源 */
		if (!ledsource[i]) {
			dev_err(&dev->dev, "No MEM resource for always on\n");
			return -ENXIO;
		}
		ressize[i] = resource_size(ledsource[i]);	
	}	
    
    IMX6U_CCM_CCGR1 = ioremap(ledsource[0]->start, ressize[0]);
	SW_MUX_GPIO1_IO018 = ioremap(ledsource[1]->start, ressize[1]);
  	SW_PAD_GPIO1_IO018 = ioremap(ledsource[2]->start, ressize[2]);
	GPIO1_DR = ioremap(ledsource[3]->start, ressize[3]);
	GPIO1_GDIR = ioremap(ledsource[4]->start, ressize[4]);

    val = readl(IMX6U_CCM_CCGR1);
    val &= ~(3<<26);
    val |=  3<<26;      
    writel(val, IMX6U_CCM_CCGR1); //使能GPIO_1时钟

    writel(5, SW_MUX_GPIO1_IO018); //复用为GPIO
	writel(0xF080, SW_PAD_GPIO1_IO018);//待定  设置电气特性

    val = readl(GPIO1_GDIR);        
	val &= ~(1 << 18);			
	val &= 0 << 18;			    //设置GPIO方向为输入
	writel(val, GPIO1_GDIR);

    key_dev.owner = THIS_MODULE;
    alloc_chrdev_region(&devid, 0, KeyDEV_CNT, KeyDEV_NAME);      //分配设备号
    cdev_init(&key_dev,&key_fops);                                //绑定文件操作集合
    cdev_add(&key_dev,devid,KeyDEV_CNT);                          //绑定设备号,注册字符设备
    class = class_create(THIS_MODULE,KeyDEV_NAME);                //创建类
    device = device_create(class, NULL, devid, NULL, KeyDEV_NAME);
	if (IS_ERR(device)) {
		return PTR_ERR(device);
	}
    return 0;
}

static int Keyremove(struct platform_device *dev)
{
    return 0;
}

static const struct of_device_id key_of_match[] = {
	{ .compatible = "MyKeyPlatformWithDTB" },
	{ /* Sentinel */ }
};

struct platform_driver key_driver = {
    .driver = {                 //驱动程序的属性，用来匹配设备(设备树方法)
        .name	= "MyPlatformKey",
        .of_match_table = key_of_match,
    },
    .probe = Keyprobe,         //probe元素，匹配成功后执行
    .remove = Keyremove,        //remove元素，卸载后执行
};

/*
 * @description	: 驱动模块加载函数
 * @param 		: 无
 * @return 		: 
 */
static int __init keydriver_init(void)
{
	return platform_driver_register(&key_driver);
}

/*
 * @description	: 驱动模块卸载函数
 * @param 		: 无
 * @return 		: 
 */
static void __exit keydriver_exit(void)
{
	platform_driver_unregister(&key_driver);
}

module_init(keydriver_init);
module_exit(keydriver_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZiXie");